package com.peng.ppscalelibrary.BleManager.Manager;


import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.inuker.bluetooth.library.BluetoothClient;
import com.inuker.bluetooth.library.connect.listener.BleConnectStatusListener;
import com.inuker.bluetooth.library.connect.options.BleConnectOptions;
import com.inuker.bluetooth.library.connect.response.BleConnectResponse;
import com.inuker.bluetooth.library.connect.response.BleNotifyResponse;
import com.inuker.bluetooth.library.connect.response.BleWriteResponse;
import com.inuker.bluetooth.library.model.BleGattProfile;
import com.inuker.bluetooth.library.search.SearchRequest;
import com.inuker.bluetooth.library.search.SearchResult;
import com.inuker.bluetooth.library.search.response.SearchResponse;
import com.inuker.bluetooth.library.utils.BluetoothLog;
import com.inuker.bluetooth.library.utils.ByteUtils;
import com.peng.ppscalelibrary.BleManager.Interface.BleBMDJConnectInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleBMDJExitInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleBMDJInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleBMDJParttenInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleBMDJPassivityDisconnectInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleConnectFliterInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleDataProtocoInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleDataStateInterface;
import com.peng.ppscalelibrary.BleManager.Interface.BleHeartRateInterface;
import com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel;
import com.peng.ppscalelibrary.BleManager.Model.BleDeviceModel;
import com.peng.ppscalelibrary.BleManager.Model.BleUserModel;

import java.util.List;
import java.util.UUID;

import static com.inuker.bluetooth.library.Code.REQUEST_SUCCESS;
import static com.inuker.bluetooth.library.Constants.STATUS_DISCONNECTED;
import static com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel.ADORE_SCALE;
import static com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel.CF367_SCALE;
import static com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel.ELECTRONIC_SCALE;
import static com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel.HEARTRATE_SCALE;
import static com.peng.ppscalelibrary.BleManager.Model.BleConnectFliterModel.WEIGHT_SCALE;

public class BleManager {


    private static final int UPDATE_UI = 0X02;
    private static BleManager bleManager;

    private static BluetoothClient mBleClient;
    private BleConnectFliterManager mFliterManager;
    private BleUserModel mUserModel;
    private boolean isBinding;
    private BleDataProtocoInterface protocoInterface;
    private BleBMDJConnectInterface bmdjConnectInterface;
    private BleBMDJInterface bmdjInterface;
    private BleBMDJParttenInterface bmdjParttenInterface;
    private BleBMDJExitInterface bmdjExitInterface;
    private BleBMDJPassivityDisconnectInterface passivityDisconnectInterface;
    private SearchResult connectedDevice;
    private UUID connectedService;
    private UUID connectedCharacter;
    private String lastReciveData;
    private BleDataProtocoManager protocoManager;
    private boolean recivingAdvData;

    private final BleConnectStatusListener mConnectStatusListener = new BleConnectStatusListener() {
        @Override
        public void onConnectStatusChanged(String mac, int status) {
            isConnecting = false;
            BluetoothLog.v(String.format("CharacterActivity.onConnectStatusChanged status = %d", status));
            if (status == STATUS_DISCONNECTED) {
                if (passivityDisconnectInterface != null) {
                    passivityDisconnectInterface.passivityDisconnect();
                }
            }
        }
    };
    private boolean isConnecting = false;

    public static BleManager shareInstance(Context context) {
        if (bleManager == null) {
            synchronized (BleManager.class) {
                if (bleManager == null) {
                    mBleClient = new BluetoothClient(context.getApplicationContext());
                    bleManager = new BleManager();
                }
            }
        }
        return bleManager;
    }

    public BleManager() {
        mFliterManager = new BleConnectFliterManager();
        protocoManager = new BleDataProtocoManager();
    }

    public static boolean isBluetoothEnabled() {
        return BluetoothAdapter.getDefaultAdapter().isEnabled();
    }

    public void searchDevice(boolean isBinding, List<BleDeviceModel> deviceList, BleUserModel userModel, BleDataProtocoInterface protocoInterface) {
        this.isConnecting = false;
        this.isBinding = isBinding;
        this.mUserModel = userModel;
        this.protocoInterface = protocoInterface;
        this.mFliterManager.setBindingList(deviceList);
        this.recivingAdvData = false;
        this.lastReciveData = "";
        connectedService = null;
        connectedCharacter = null;
        bmdjParttenInterface = null;
        bmdjConnectInterface = null;
        bmdjInterface = null;
        this.bmdjExitInterface = null;
        this.passivityDisconnectInterface = null;
        mBleClient.stopSearch();
        disconnectDevice();
        SearchRequest request = null;
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

            request = new SearchRequest.Builder()
                    .searchBluetoothLeDevice(1000, 1000)
                    .build();
        } else {

            request = new SearchRequest.Builder()
                    .searchBluetoothLeDevice(300000)
                    .build();
        }

        mBleClient.search(request, mSearchResponse);
    }

    public void connectBMDJ(List<BleDeviceModel> deviceList, BleBMDJConnectInterface connectInterface) {
        this.bmdjConnectInterface = connectInterface;
        this.lastReciveData = "";
        this.connectedService = null;
        this.connectedCharacter = null;
        this.mFliterManager.setBindingList(deviceList);
        protocoInterface = null;
        this.bmdjInterface = null;
        this.bmdjParttenInterface = null;
        this.bmdjExitInterface = null;
        this.passivityDisconnectInterface = null;
        mBleClient.stopSearch();
        disconnectDevice();
        SearchRequest request = null;
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(1000, 1000).build();
        } else {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(300000).build();
        }

        mBleClient.search(request, bmdjSearchResponse);
    }

    public void reSearchDevice() {
        mBleClient.stopSearch();
        disconnectDevice();
        recivingAdvData = false;
        SearchRequest request = null;
        if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(1000, 1000).build();
        } else {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(300000).build();
        }

        mBleClient.search(request, mSearchResponse);
    }

    public void search() {
        mBleClient.stopSearch();
        recivingAdvData = false;
        SearchRequest request = null;
        if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(1000, 1000).build();
        } else {

            request = new SearchRequest.Builder().searchBluetoothLeDevice(300000).build();
        }

        mBleClient.search(request, mSearchResponse);
    }


    private void disconnectADVDevice() {
        this.passivityDisconnectInterface = null;
        if (connectedDevice != null) {
            String connectedDeviceName = connectedDevice.getName();
            if (connectedDeviceName.equals(ELECTRONIC_SCALE) ||
                    connectedDeviceName.equals(ADORE_SCALE) ||
                    connectedDeviceName.equals(CF367_SCALE) ||
                    connectedDeviceName.equals(HEARTRATE_SCALE) ||
                    connectedDeviceName.equals(WEIGHT_SCALE)
            ) {

            } else {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mBleClient.disconnect(connectedDevice.getAddress());
                    }
                }, 500);
            }
        }
    }

    public void disconnectDevice() {
        this.passivityDisconnectInterface = null;
        if (connectedDevice != null) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mBleClient.disconnect(connectedDevice.getAddress());
                }
            }, 500);

        }
    }

    public void stopSearch() {
        mBleClient.stopSearch();
        this.passivityDisconnectInterface = null;
        if (connectedDevice != null) {
            if (connectedDevice.getName().equals(ELECTRONIC_SCALE) || connectedDevice.getName().equals(CF367_SCALE)) {
                mBleClient.disconnect(connectedDevice.getAddress());
            }
        }
    }

    public void dissconnectBMScale() {
        mBleClient.stopSearch();
        this.passivityDisconnectInterface = null;
        if (connectedDevice != null) {
            mBleClient.write(connectedDevice.getAddress(), connectedService, connectedCharacter, protocoManager.sendExitMBDJData2Scale(), new BleWriteResponse() {
                @Override
                public void onResponse(int code) {
                    mBleClient.disconnect(connectedDevice.getAddress());
                }
            });
        }
    }

    int num = 0;

    public void deleteAdoreHistoryData() {
        if (connectedDevice != null && connectedService != null && connectedCharacter != null) {
            final byte[] bytes = BleDataProtocoManager.deleteAdoreHistoryData();

            mBleClient.write(connectedDevice.getAddress(), connectedService, connectedCharacter, bytes, new BleWriteResponse() {
                @Override
                public void onResponse(int code) {
                    Log.d("BleManager", " deleteAdoreHistoryData code = " + code);
                    if (code == REQUEST_SUCCESS) {
                        disconnectDevice();
                    } else {
                        if (bytes.length > 0) {
                            num += 1;
                            if (num >= 3) {
                                num = 0;
                                disconnectDevice();
                            } else {
                                new Handler().postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        deleteAdoreHistoryData();
                                    }
                                }, 500);
                            }
                        } else {
                            disconnectDevice();
                        }
                    }
                }
            });
        }
    }


    private final SearchResponse bmdjSearchResponse = new SearchResponse() {
        @Override
        public void onSearchStarted() {
            BluetoothLog.d("onSearchStarted---bmdj");

        }

        @Override
        public void onDeviceFounded(final SearchResult searchResult) {
            if (mFliterManager.inBindedList2ConnectDevice(searchResult)) {
                // 连接设备
                stopSearch();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        connectBMDJDevice(searchResult);
                        connectedDevice = searchResult;
                    }
                }, 700);

            }
        }

        @Override
        public void onSearchStopped() {
            BluetoothLog.v("------------------------ onSearchStopped bmdj ------------------------");
        }

        @Override
        public void onSearchCanceled() {
            BluetoothLog.v("------------------------ onSearchCanceled bmdj ------------------------");
        }
    };


    private final SearchResponse mSearchResponse = new SearchResponse() {
        long startTime = System.currentTimeMillis();

        @Override
        public void onSearchStarted() {
            startTime = System.currentTimeMillis();
        }

        @Override
        public void onDeviceFounded(final SearchResult device) {
            onFindDevice(device);
        }

        @Override
        public void onSearchStopped() {
            BluetoothLog.v("------------------------ onSearchStopped ------------------------");
        }

        @Override
        public void onSearchCanceled() {
            BluetoothLog.v("------------------------ onSearchCanceled ------------------------");
        }
    };

    private void onFindDevice(final SearchResult device) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 绑定新设备
                if (isBinding) {
                    // 目标设备过滤
                    if (mFliterManager.exceptBindedList2ConnectDevice(device)) {
                        BluetoothLog.v("exceptBindedList2ConnectDevice----" + device.toString());

                        if (mFliterManager.needNotConnect(device)) {
                            BluetoothLog.v("needNotConnect----" + device.toString() +
                                    " name = " + device.getName() + " 广播数据 = " + ByteUtils.byteToString(device.scanRecord));
                            recivingAdvData = true;
                            String finalData = protocoManager.analysisSearchData(device, mFliterManager.getMatchedFliterModel());
                            BluetoothLog.v("finalData----" + finalData);
                            if (finalData.length() > 0) {
                                if (!lastReciveData.equals(finalData)) {
                                    lastReciveData = finalData;

                                    if (mFliterManager.getMatchedFliterModel().getScaleName().equals(HEARTRATE_SCALE)) {
                                        protocoManager.heartRateScaleProtocol(finalData, mFliterManager.getMatchedFliterModel(), device.getAddress(), mUserModel, protocoInterface, new BleHeartRateInterface() {
                                            @Override
                                            public void heartRatingState(boolean isHeartRatingEnd) {
                                                if (isHeartRatingEnd) {
//                                                    connectDevice(device);
//                                                    connectedDevice = device;
                                                    Message message = new Message();
                                                    message.what = UPDATE_UI;
                                                    message.obj = device;
                                                    handler.sendMessage(message);
                                                }

                                            }
                                        });
                                    } else {
                                        protocoManager.energyScaleProtocol(finalData, mFliterManager.getMatchedFliterModel(), device.getAddress(), mUserModel, protocoInterface);
                                        if (protocoManager.isLockedData(finalData)) {
//                                            stopSearch();
                                            // 连接设备
                                            connectDevice(device);
                                            connectedDevice = device;
                                        }
                                    }

                                }
                            }
                        } else {
//                                if (!recivingAdvData) {
//                                    stopSearch();
                            // 连接设备
//                            connectDevice(device);
//                            connectedDevice = device;
                            Message message = new Message();
                            message.what = UPDATE_UI;
                            message.obj = device;
                            handler.sendMessage(message);
//                                }
                        }
                    }
                } else {
                    // 连接旧设备
                    if (mFliterManager.inBindedList2ConnectDevice(device)) {

                        if (mFliterManager.needNotConnect(device)) {
                            BluetoothLog.v("needNotConnect----" + device.toString() +
                                    " name = " + device.getName() + " 广播数据 = " + ByteUtils.byteToString(device.scanRecord));
                            recivingAdvData = true;
                            String finalData = protocoManager.analysisSearchData(device, mFliterManager.getMatchedFliterModel());
                            BluetoothLog.v("finalData----" + finalData);
                            if (finalData.length() > 0) {
                                if (!lastReciveData.equals(finalData)) {
                                    lastReciveData = finalData;
                                    if (mFliterManager.getMatchedFliterModel().getScaleName().equals(HEARTRATE_SCALE)) {
                                        protocoManager.heartRateScaleProtocol(finalData, mFliterManager.getMatchedFliterModel(), device.getAddress(), mUserModel, protocoInterface, new BleHeartRateInterface() {
                                            @Override
                                            public void heartRatingState(boolean isHeartRatingEnd) {
                                                if (isHeartRatingEnd) {
                                                    connectDevice(device);
                                                    connectedDevice = device;
                                                }

                                            }
                                        });
                                    } else {
                                        protocoManager.energyScaleProtocol(finalData, mFliterManager.getMatchedFliterModel(), device.getAddress(), mUserModel, protocoInterface);
                                        if (protocoManager.isLockedData(finalData)) {
//                                            stopSearch();
                                            // 连接设备
                                            connectDevice(device);
                                            connectedDevice = device;
                                        }
                                    }


                                }
                            }
                        } else {
//                                if (!recivingAdvData) {
//                                    stopSearch();
                            // 连接设备
                            Message message = new Message();
                            message.what = UPDATE_UI;
                            message.obj = device;
                            handler.sendMessage(message);
//                                }
                        }
                    }
                }
            }
        }).start();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(final Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    deleteAdoreHistoryData();
                    break;
                case UPDATE_UI:
                    final SearchResult device = (SearchResult) msg.obj;
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (device != null){
                                connectDevice(device);
                                connectedDevice = device;
                            }
                        }
                    }, 700);
                    break;
            }
        }
    };

    private void connectBMDJDevice(final SearchResult device) {
        final String deviceMac = device.getAddress();
        mBleClient.registerConnectStatusListener(deviceMac, mConnectStatusListener);

        BleConnectOptions options = new BleConnectOptions.Builder()
                .setConnectRetry(2)
                .setConnectTimeout(7000)
                .setServiceDiscoverRetry(2)
                .setServiceDiscoverTimeout(7000)
                .build();
        mBleClient.connect(deviceMac, options, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile profile) {
                mFliterManager.monitirBMDJResponse(code, profile, new BleConnectFliterInterface() {
                    @Override
                    public void targetResponse(final UUID service, final UUID character, final BleConnectFliterModel fliterModel) {

                        connectedService = service;
                        connectedCharacter = character;
                        mBleClient.notify(deviceMac, service, character, new BleNotifyResponse() {
                            @Override
                            public void onNotify(UUID service, UUID character, byte[] value) {
                                String reciveData = String.format("%s", ByteUtils.byteToString(value));
                                if (!lastReciveData.equals(reciveData)) {
                                    lastReciveData = reciveData;
                                    BluetoothLog.v("reciveData--------- " + reciveData);
                                    if (bmdjConnectInterface != null) {
                                        protocoManager.bmScaleStatusProtocol(reciveData, fliterModel, bmdjConnectInterface);
                                    }
                                    if (bmdjInterface != null) {
                                        protocoManager.bmScaleProtocol(reciveData, fliterModel, bmdjInterface);
                                    }
                                    if (bmdjParttenInterface != null) {
                                        protocoManager.bmScaleStartTimingProtocol(reciveData, fliterModel, bmdjParttenInterface);
                                    }
                                    if (bmdjExitInterface != null) {
                                        protocoManager.bmScaleExitStatusProtocol(reciveData, fliterModel, bmdjExitInterface);
                                    }
                                }
                            }

                            @Override
                            public void onResponse(int code) {
                                BluetoothLog.v("reciveDataCode--------- " + code);

                            }
                        });

                        final byte[] commond = protocoManager.sendMBDJData2Scale();
                        mBleClient.write(deviceMac, service, character, commond, new BleWriteResponse() {
                            @Override
                            public void onResponse(int code) {

                            }
                        });
                    }

                    @Override
                    public void target2Write(final UUID service, final UUID character, BleConnectFliterModel fliterModel) {

                    }
                });
            }
        });
    }

    private void connectDevice(final SearchResult device) {
        BluetoothLog.v("------------------------ startConnectDevice ------------------------");
        isConnecting = true;
        final String deviceMac = device.getAddress();
        mBleClient.registerConnectStatusListener(deviceMac, mConnectStatusListener);

        BleConnectOptions options = new BleConnectOptions.Builder()
                .setConnectRetry(2)
                .setConnectTimeout(7000)
                .setServiceDiscoverRetry(2)
                .setServiceDiscoverTimeout(7000)
                .build();
        mBleClient.connect(deviceMac, options, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile profile) {
                isConnecting = false;
                if (code == REQUEST_SUCCESS) {
                    mBleClient.stopSearch();

                    final BleConnectFliterModel deviceModel = mFliterManager.getTargetDevice(device);

                    mFliterManager.monitorTargetResponse(code, profile, new BleConnectFliterInterface() {
                        @Override
                        public void target2Write(UUID service, UUID character, BleConnectFliterModel fliterModel) {
                            connectedService = service;
                            connectedCharacter = character;
                            if (deviceModel != null) {
                                fliterModel = deviceModel;
                            }

                            List<byte[]> commonds = protocoManager.sendData(fliterModel, mUserModel);
                            write(deviceMac, service, character, commonds);
                        }

                        @Override
                        public void targetResponse(UUID service, UUID character, final BleConnectFliterModel fliterModel) {
                            mBleClient.notify(deviceMac, service, character, new BleNotifyResponse() {
                                @Override
                                public void onNotify(UUID service, UUID character, byte[] value) {
                                    String reciveData = String.format("%s", ByteUtils.byteToString(value));

                                    if (!lastReciveData.equals(reciveData)) {
                                        BluetoothLog.v("reciveData---------  " + reciveData + "   lastReciveData---------  " + lastReciveData);

                                        lastReciveData = reciveData;
                                        protocoManager.analysisReciveData(reciveData, deviceMac, fliterModel, mUserModel, protocoInterface, new BleDataStateInterface() {
                                            @Override
                                            public void sendHistoryData() {
                                                num = 0;
                                                handler.sendEmptyMessage(0);
                                            }
                                        });
                                    }
                                }

                                @Override
                                public void onResponse(int code) {
                                    BluetoothLog.v("reciveDataCode--------- " + code);
                                    connectedDevice = device;
                                }
                            });
                        }
                    });
                } else {
                    disconnectADVDevice();
                }
            }
        });

    }

    private void write(final String mac, final UUID service, final UUID character, final List<byte[]> commond) {
        mBleClient.write(mac, service, character, commond.get(0), new BleWriteResponse() {
            @Override
            public void onResponse(int code) {
                if (code == REQUEST_SUCCESS) {
                    String writeData = String.format("%s", ByteUtils.byteToString(commond.get(0)));
                    BluetoothLog.v("writeSuccess--------- " + writeData);

                    commond.remove(0);
                    if (!commond.isEmpty()) {
                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                write(mac, service, character, commond);
                            }
                        }, 700);
                    } else {
                        disconnectADVDevice();
                    }
                } else {
                    disconnectADVDevice();
                }
            }
        });
    }


    public void intoBMDJPattern(final BleBMDJParttenInterface parttenInterface) {
//        this.bmdjConnectInterface = null;
//        this.bmdjInterface = null;
        this.bmdjParttenInterface = parttenInterface;
    }

    public void BMDJTimeInterval(final BleBMDJInterface bmdjInterface) {
//        this.bmdjConnectInterface = null;
//        this.bmdjParttenInterface = null;
        this.bmdjInterface = bmdjInterface;
    }

    public void exitBMDJPattern(final BleBMDJExitInterface exitInterface) {
        this.bmdjExitInterface = exitInterface;
    }

    public void passivityDisconnect(final BleBMDJPassivityDisconnectInterface passivityDisconnectInterface) {
        this.passivityDisconnectInterface = passivityDisconnectInterface;
    }

}
